#pragma once
#include<iostream>
#include"ResourceUtil.h"
#include"LocInfo.h"
using namespace std;

//静态类，负责数据修改 提取。
//此类的操作都在同一个行块，多行块操作应在上层分行块调用来提升性能。
class RowOperator{ //不存储数据，仅负责组织调用
private:

    static vector<LocInfo> generateInsertLocInfoVec(const int16_t& blockNo, const int& startInd, const int& count){
        vector<LocInfo> insertLocInfoVec;
        const int& endInd = startInd + count;
        for(int ind = startInd; ind < endInd; ind++){
            insertLocInfoVec.push_back(LocInfo(blockNo, ind));
        }
        return insertLocInfoVec;
    }


    static vector<string> getColNameVec(const map<string, vector<Basic*>>& colDatas){
        vector<string> colNameVec;
        for(const auto& it : colDatas){
            colNameVec.push_back(it.first);
        }
        return colNameVec;
    }


    //获取在同一行的Block里的多行数据    locInfoVec应具有相同的blockNo
    static void getRowsData(const vector<ResourceManage*> blockVec, map<string, vector<Basic*>>& rowsData, const set<int>& locInfoSet, const bool& snapShotRead){
        for(size_t i = 0; i < blockVec.size(); i++){
            Block* tmpBlock = (Block*)blockVec[i];
            vector<Basic*>& colData = rowsData[tmpBlock->getResourceInfo().getColName()];
            for(const int& ind : locInfoSet){  //磁盘顺序访问
                Basic* tmpBasicData = snapShotRead ? tmpBlock->getSnapShotData(ind) : tmpBlock->getData(ind);
                colData.push_back(BasicUtil::getCopyBasicData(tmpBasicData));
            }
        }
    }


    static set<int> getUnDelLocInfo(BlockDel* blockDel, const set<int>& locInfoSet, const bool& snapShotRead){
        set<int> unDelLocInfo;
        for(const int& locInfo : locInfoSet){
            if(!(snapShotRead ? blockDel->snapShotIsDel(locInfo) : blockDel->isDel(locInfo))){
                unDelLocInfo.insert(locInfo);
            }
        }
        return unDelLocInfo;
    }


    static void getSnapShotRowsData(const vector<ResourceManage*>& blockVec, map<string, vector<Basic*>>& rowsData, const set<int>& locInfoSet){
        ResourceUtil::getSnapShotLock(blockVec, READ);  //将资源上快照锁 防止读时快照更新
        getRowsData(blockVec, rowsData, locInfoSet, true);
        ResourceUtil::releaseSnapShotLock(blockVec);
    }


    static set<int> getSnapShotUnDelLocInfo(BlockDel* blockDel, const set<int>& locInfoSet){
        blockDel->getSnapShotLock(READ);
        const set<int>& unDelLocInfo = getUnDelLocInfo(blockDel, locInfoSet, true);
        blockDel->releaseSnapShotLock();
        return unDelLocInfo;
    }


    //保证获取一致的行
    //获取在同一行的Block里的多行数据 减少请求资源池                 locInfoVec应具有相同的blockNo
    static void getCurrentRowsData(const vector<ResourceManage*>& blockVec, map<string, vector<Basic*>>& rowsData, const set<int>& locInfoSet, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        //为资源上读锁
        ResourceUtil::getResLock(blockVec, lockType, transaction);
        getRowsData(blockVec, rowsData, locInfoSet, false);
        //如果不在事务里就解锁
        if(transaction == nullptr){
            ResourceUtil::releaseResLock(blockVec);     //在事务里的话 事务结束后解锁资源 不用在这里解锁
        }
    }


    static set<int> getCurrentUnDelLocInfo(BlockDel* blockDel, const set<int>& locInfoSet, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        const bool& isInTransaction = transaction != nullptr;
        isInTransaction ? transaction->getResLock(blockDel, lockType) : blockDel->getResLock(lockType);
        const set<int>& unDelLocInfo = getUnDelLocInfo(blockDel, locInfoSet, false);
        if(!isInTransaction){
            blockDel->releaseResLock();
        }
        return unDelLocInfo;
    }


    static map<string, vector<Basic*>> getSnapShotOrCurrentRowsData(const TableInfo* tableInfo, const vector<string>& colNameVec, const map<int16_t, set<int>>& mergeSortLocInfo, const bool& snapShotRead, const LOCKTYPE& lockType, Transaction* transaction){
        map<string, vector<Basic*>> rowsData;   //按列存储
        for(const auto& it : mergeSortLocInfo){
            const set<int>& tmpIndSet = it.second;
            if(tmpIndSet.empty()){ continue; }
            const int16_t& blockNo = it.first;
            const vector<ResourceInfo>& rowBlockInfo = ResourceUtil::getRowBlockInfo(tableInfo, colNameVec, blockNo);
            const vector<ResourceManage*>& rowBlock = ResourceUtil::getResVec(rowBlockInfo, transaction);
            string exceptionInfo = "";
            try {
                snapShotRead ? getSnapShotRowsData(rowBlock, rowsData, tmpIndSet) :
                               getCurrentRowsData(rowBlock, rowsData, tmpIndSet, lockType, transaction);
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ResourceUtil::releaseHoldLock(rowBlock);}   //如果不在事务管理 最终需要释放持有
            if(exceptionInfo != ""){ throw exceptionInfo; }   //继续向上抛
        }
        return rowsData;
    }

    static map<int16_t, set<int>> getSnapShotOrCurrentUnDelLocInfo(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, const bool& snapShotRead, const LOCKTYPE& lockType, Transaction* transaction){
        map<int16_t, set<int>> unDelLocInfo;
        const string& baseName = tableInfo->getBaseName(), tableName = tableInfo->getTableName();
        for(const auto& it : mergeSortLocInfo){
            const int16_t& blockNo = it.first;
            const ResourceInfo& resInfo = ResourceInfo(baseName, tableName, blockNo);
            BlockDel* blockDel = (BlockDel*)ResourceUtil::getRes(resInfo, transaction);
            string exceptionInfo = "";
            try {
                const set<int>& tmpUnDelLocInfo = snapShotRead ?
                                                               getSnapShotUnDelLocInfo(blockDel, it.second) :
                                                               getCurrentUnDelLocInfo(blockDel, it.second, lockType, transaction);
                unDelLocInfo[blockNo] = tmpUnDelLocInfo;
            }  catch (string str) {
                exceptionInfo = str;
            }
            if(transaction == nullptr){ blockDel->releaseHoldLock(); };        //如果不在事务管理 最终需要释放持有
            if(exceptionInfo != ""){ throw exceptionInfo; }                           //继续向上抛
        }
        return unDelLocInfo;
    }



    static int blockAddRowsData(const TableInfo* tableInfo, const map<string, vector<Basic*>>& addDatas, const int16_t& blockNo, Transaction* transaction){
        const vector<ResourceInfo>& rowBlockInfo = ResourceUtil::getRowBlockInfo(tableInfo, blockNo);
        const vector<ResourceManage*>& rowBlock = ResourceUtil::getResVec(rowBlockInfo, transaction);
        ResourceUtil::getResLock(rowBlock, WRITE, transaction);       //没获取到锁会抛异常
        //获取锁之后再获取size
        const int& unAddDataListSize = ((Block*)rowBlock.front())->getDataListSize();
        for(ResourceManage* res : rowBlock){
            ((Block*)res)->addData(addDatas.at(res->getResourceInfo().getColName()));
        }
        //持有锁 资源锁 在事务提交或者回滚后释放
        return unAddDataListSize;
    }


    static void blockDelRowsData(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, Transaction* transaction){
        const string& baseName = tableInfo->getBaseName(), tableName = tableInfo->getTableName();
        for(const auto& it : mergeSortLocInfo){
            const int16_t& blockNo = it.first;
            const ResourceInfo& resInfo = ResourceInfo(baseName, tableName, blockNo);
            BlockDel* blockDel = (BlockDel*)ResourceUtil::getRes(resInfo, transaction);
            transaction->getResLock(blockDel, WRITE);
            for(const int& locInfo : it.second){
                blockDel->delEle(locInfo);
            }
            //持有锁 资源锁 在事务完成后释放
        }
    }


    static void blockModRowsData(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, const map<string, vector<Basic*>>& modDatas, Transaction* transaction){
        const vector<string>& colNameVec = getColNameVec(modDatas);
        size_t dataStartInd = 0;
        for(const auto& blockLocInfo : mergeSortLocInfo){
            const vector<ResourceInfo>& rowBlockInfo = ResourceUtil::getRowBlockInfo(tableInfo, colNameVec, blockLocInfo.first);
            const vector<ResourceManage*>& rowBlock = ResourceUtil::getResVec(rowBlockInfo, transaction);
            ResourceUtil::getResLock(rowBlock, WRITE, transaction);       //没获取到锁会抛异常
            const set<int>& indSet = blockLocInfo.second;
            vector<int> indVec(indSet.begin(), indSet.end());
            int blockInd = 0;
            for(const string& colName : colNameVec){
                const vector<Basic*> dataVec = modDatas.at(colName);
                vector<Basic*> subDataVec(dataVec.begin() + dataStartInd, dataVec.begin() + dataStartInd + indVec.size());
                ((Block*)rowBlock[blockInd++])->modData(indVec, subDataVec);
            }
            dataStartInd += indVec.size();
        }
    }


    static void indexAddOrDelDatas(const ResourceInfo& resInfo, const vector<pair<Basic*, size_t>>& addDatas, const vector<LocInfo>& locInfoVec, const bool& isAdd, Transaction* transaction){
        SkipListIndex* index = (SkipListIndex*)ResourceUtil::getRes(resInfo, transaction);
        transaction->getResLock(index, WRITE);              //没获取到锁会抛异常
        //需要拷贝， add:原数据给block  del:删除成功会把数据给日志    没操作成功会在内部释放
        for(const auto& it : addDatas){
            Basic* opData = isAdd ? BasicUtil::getCopyBasicData(it.first) : it.first;   //如果是删除操作的话 数据在读的时候就拷贝了 所以在这不需要拷贝
            LocInfo* locInfo = new LocInfo(locInfoVec[it.second]);
            isAdd ? index->put(opData, locInfo) : index->remove(opData, locInfo);
        }
        //持有锁 资源锁 在事务提交或者回滚后释放
    }


    static void indexAddOrDelRowsData(const TableInfo* tableInfo, const vector<LocInfo>& locInfoVec, const map<string, vector<Basic*>>& addDatas, const bool& isAdd, Transaction* transaction){
        for(const auto& colAddDatas : addDatas){
            if(!tableInfo->getColInfo(colAddDatas.first)->getIsWithIndex()){
                continue;
            }
            const map<ResourceInfo, vector<pair<Basic*, size_t>>>& mergeIndexInfoVec = ResourceUtil::getMergeIndexOrBitMapInfoAccrodData(tableInfo, colAddDatas.first, colAddDatas.second, true);
            for(const auto& blockAddDatas : mergeIndexInfoVec){
                indexAddOrDelDatas(blockAddDatas.first, blockAddDatas.second, locInfoVec, isAdd, transaction);
            }
        }
    }


    static void indexAddOrDelRowsData(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, const map<string, vector<Basic*>>& addDatas, const bool& isAdd, Transaction* transaction){
        const vector<LocInfo>& locInfoVec = LocInfoUtil::mergeSortLocInfoToLocInfo(mergeSortLocInfo);
        indexAddOrDelRowsData(tableInfo, locInfoVec, addDatas, isAdd, transaction);
    }


    static void bitMapAddDatas(const ResourceInfo& resInfo, const vector<pair<Basic*, size_t>>& addDatas, Transaction* transaction){
        BitMap* bitMap = (BitMap*)ResourceUtil::getRes(resInfo, transaction);
        transaction->getResLock(bitMap, WRITE);          //没获取到锁会抛异常
        for(const auto& it : addDatas){
            bitMap->put(it.first->getHashVal());
        }
        //持有锁 资源锁 在事务提交或者回滚后释放
    }


    static void bitMapAddRowsData(const TableInfo* tableInfo, const map<string, vector<Basic*>>& addDatas, Transaction* transaction){
        for(const auto& colAddDatas : addDatas){
            const map<ResourceInfo, vector<pair<Basic*, size_t>>>& mergeBitMapInfoVec = ResourceUtil::getMergeIndexOrBitMapInfoAccrodData(tableInfo, colAddDatas.first, colAddDatas.second, false);
            for(const auto& blockAddDatas : mergeBitMapInfoVec){
                bitMapAddDatas(blockAddDatas.first, blockAddDatas.second, transaction);
            }
        }
    }


public:

    //传入的 二维locinfo数组应是按blockNo排序分区 且小组ind有序的
    //当前读    传入事务之后为可重复读     可以选择上写锁 lockForWrite
    static map<string, vector<Basic*>> currentReadRowsData(const TableInfo* tableInfo, const vector<string>& colNameVec, const map<int16_t, set<int>>& mergeSortLocInfo, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return getSnapShotOrCurrentRowsData(tableInfo, colNameVec, mergeSortLocInfo, false, lockType, transaction);
    }

    //传入的 二维locinfo数组应是按blockNo排序分区 且小组ind有序的
    //快照读
    static map<string, vector<Basic*>> snapShotReadRowsData(const TableInfo* tableInfo, const vector<string>& colNameVec, const map<int16_t, set<int>>& mergeSortLocInfo){
        return getSnapShotOrCurrentRowsData(tableInfo, colNameVec, mergeSortLocInfo, true, READ, nullptr);
    }


    //当前读 返回没有被删除的位置
    static map<int16_t, set<int>> currentGetUnDelLocInfo(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        return getSnapShotOrCurrentUnDelLocInfo(tableInfo, mergeSortLocInfo, false, lockType, transaction);
    }

    //快照读 返回没有被删除的位置
    static map<int16_t, set<int>> snapShotGetUnDelLocInfo(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo){
        return getSnapShotOrCurrentUnDelLocInfo(tableInfo, mergeSortLocInfo, true, READ, nullptr);
    }
                                                                                                //按列存 需包含所有列
    static void addRowsData(const TableInfo* tableInfo, const map<string, vector<Basic*>>& addDatas, Transaction* transaction){
        const int16_t& blockNo = tableInfo->getRandomBlockNo();
        const int& unAddDataListSize = blockAddRowsData(tableInfo, addDatas, blockNo, transaction);
        const vector<LocInfo> locInfoVec = generateInsertLocInfoVec(blockNo, unAddDataListSize, addDatas.begin()->second.size());
        indexAddOrDelRowsData(tableInfo, locInfoVec, addDatas, true, transaction);
        bitMapAddRowsData(tableInfo, addDatas, transaction);
    }

    static void delRowsData(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, Transaction* transaction){
        blockDelRowsData(tableInfo, mergeSortLocInfo, transaction);
        const map<string, vector<Basic*>>& rowsData = currentReadRowsData(tableInfo, tableInfo->getColNameVec(true), mergeSortLocInfo, READ, transaction);
        //bitmap不做删除操作
        indexAddOrDelRowsData(tableInfo, mergeSortLocInfo, rowsData, false, transaction);
    }

    static void modRowsData(const TableInfo* tableInfo, const map<int16_t, set<int>>& mergeSortLocInfo, const map<string, vector<Basic*>>& modDatas , Transaction* transaction){
        //先把旧的读出来再修改 之后要修改 直接上写锁
        const map<string, vector<Basic*>>& rowsOldData = currentReadRowsData(tableInfo, tableInfo->getColNameVec(true), mergeSortLocInfo, WRITE, transaction);
        blockModRowsData(tableInfo, mergeSortLocInfo, modDatas, transaction);
        indexAddOrDelRowsData(tableInfo, mergeSortLocInfo, rowsOldData, false, transaction);
        indexAddOrDelRowsData(tableInfo, mergeSortLocInfo, modDatas, true, transaction);
        bitMapAddRowsData(tableInfo, modDatas, transaction);
    }


};
